package hardwareToSQL;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;

import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import hardwareToSQL.pruningAlgorithm.*;


public class RowRecord{

	//Hashtable to store the <columnName, value> pair 
	private Hashtable<String, Number> nameValueDictionary;
	//String array that contains the column names correspond 
	//to the table name
	private String[] columnNames;

	/**Name for the group of data types held in this row should 
	 * correspond to the table name this row will be inserted to */
	private String name;

	private Properties dataToTables;

	/**Algorithm used for pruning the data */
	private Pruning algorithm;

	private int timeInterval;
	private Timer timer;

	/**Record the times that the row is updated */
	public int timesUpdated;

	public RowRecord(String name, Pruning algorithm, int timeInterval){
		this.name = name;
		this.algorithm = algorithm;
		this.timeInterval = timeInterval;

		//Initialize this row given its name using the property file.
		init();
	}

	public String getName(){
		return this.name;
	}


	private void init(){

		//Load and initialize the property file that will tell the
		//row how its to be created based on the table name it
		//corresponds to
		try {
			dataToTables = new Properties();

			dataToTables.load(new FileInputStream
					("properties/dataToTables.properties"));

		} catch (FileNotFoundException e) {
			System.err.print("\nFailed to load property file\n");
			System.exit(1);
		} catch (IOException e) {
			System.err.print("\nFailed to load property file\n");
			System.exit(1);
		} catch (NullPointerException e) {
			System.err.print("\nFailed to load property file\n");
			System.exit(1);
		}

		//Get the number of types the row will store
		//numOfTypes = Integer.parseInt(tables.
		//	getProperty(name + "NumOfColumns"));

		//Initialize the row and fill it up with empty values
		/*row = new int[numOfTypes];
		for(int i = 0; i< numOfTypes; i++){
			row[i] = 0;
		}*/

		nameValueDictionary = new Hashtable<String, Number>();
		//First, put the column "Timestamp" in. 
		//Because the dataToTables properties file does not specify the Timestamp column name for each table.  
		nameValueDictionary.put("Timestamp", 0.0);
		//Initialize the array for storing column names

		String nameTemp = dataToTables.getProperty(this.name);
		//System.out.printf("the name for this rowrecord is <%s>.\n",this.name);
		columnNames = nameTemp.split(",");
		for(int i=0;i<columnNames.length;i++){
			//Strip out all the white spaces
			columnNames[i] = columnNames[i].replaceAll("\\s", "");
			//put name the hashtable that stores the name value pair
			//Initialize each value to be 0.0
			nameValueDictionary.put(columnNames[i], 0.0);
		}

		timeInterval = Integer.parseInt(dataToTables.getProperty("Time"+name));
	}

	public void startTimerAt(Date firstTime, final Statement statement){
		timer = new Timer(true);
		TimerTask task = new TimerTask(){
			public void run(){
				commitToDB(statement);
			}
		};
		timer.schedule(task, firstTime, timeInterval);
	}

	/**
	 * Commit the values stored in the object to the database the the provided
	 * statement object corresponds to.
	 * @param statement the connection statement object 
	 * @return true if it's a success, false otherwise.
	 */
	public boolean commitToDB(Statement statement){
		GregorianCalendar timeNow = new GregorianCalendar();
		Timestamp ts =  new Timestamp(timeNow.getTimeInMillis());
		String columnValues = this.toSQLString(ts);
		String query = "INSERT INTO "+this.name+" "+columnValues+";";

		int rowCount = 0;
		try {
			//System.out.printf("Executing query:\n%s\n", query);
			rowCount = statement.executeUpdate(query);
		} catch (SQLException e) {
			System.err.printf("Failed to execute query:\n%s\n", query);
			e.printStackTrace();
		}
		//System.out.printf("Query executed succeffuly. %d rows are updated.\n", rowCount);
		return true;
	}
	/**Function takes a data object and inserts its value to the corresponding 
	index in the row based on its name
	 */
	public void updateRow(SensorData data){
		String columnName = data.getName();
		Number oldValue = nameValueDictionary.get(columnName);

		/**TODO: VANCE, WHY DOES THIS THROW NULL POINTER EXCEPTIONS?? */
		try{
			if(algorithm != null){
				algorithm.insertValue(data.getValue());
				nameValueDictionary.put(columnName, algorithm.returnValue());
				if (!oldValue.equals(algorithm.returnValue()))
					timesUpdated += 1;
			} else {
				nameValueDictionary.put(columnName, data.getValue());

				if (!oldValue.equals(data.getValue()))
					timesUpdated += 1;
			}
		} catch (NullPointerException e){

		}
	}

	/**Take this row and return it as an SQL statement
	 * For example: "(Timestamp, current) VALUES ("2009-06-27 13:23:30", "34.2")"
	 * Note: there's NO SPACE in front or at the end of the returned string 
	 * @param realTime
	 * @return the string, like the example
	 */
	public String toSQLString(Timestamp realTime){

		String names = "";
		String values = "";
		for(String name:columnNames){
			names = names.concat(name+",");
			values = values.concat
			(nameValueDictionary.get(name).toString()+",");
		}
		names = names.concat("Timestamp");
		values = values.concat("'"+realTime.toString()+"'");
		return "("+names+") Values ("+values+")";
	}

}